﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using System.Xml;

namespace MiniFox.Utility
{
    /// <summary>
    /// 
    /// </summary>
    public static class XmlUtility
    {
        /// <summary>
        /// 
        /// </summary>
        static XmlUtility()
        {
        }
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <typeparam name="T"></typeparam>
        ///// <returns></returns>
        //public static XmlTypeMapping CreateTypeMapping<T>()
        //{
        //    XmlReflectionImporter importer = new XmlReflectionImporter();
        //    XmlTypeMapping xmlTypeMapping = importer.ImportTypeMapping(typeof(T));
        //    return xmlTypeMapping;
        //}

        #region XmlSerializeToString
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string XmlSerializeToString<T>(T obj)
        {
            return XmlSerializeToString(obj, Encoding.UTF8);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static string XmlSerializeToString<T>(T obj, Encoding encoding)
        {
            return XmlSerializeToString(obj, encoding, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="ns"></param>
        /// <returns></returns>
        public static string XmlSerializeToString<T>(T obj, XmlSerializerNamespaces ns)
        {
            return XmlSerializeToString(obj, Encoding.UTF8, ns);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="encoding"></param>
        /// <param name="ns"></param>
        /// <returns></returns>
        public static string XmlSerializeToString<T>(T obj, Encoding encoding, XmlSerializerNamespaces ns)
        {
            string str = null;
            //XmlSerializer ser = new XmlSerializer(CreateTypeMapping<T>());
            XmlSerializer ser = new XmlSerializer(typeof(T));
            using (MemoryStream stream = new MemoryStream())
            {
                var settings = new XmlWriterSettings();
                settings.Encoding = encoding;
                XmlWriter w = XmlWriter.Create(stream, settings);
                if (ns == null)
                {
                    ns = new XmlSerializerNamespaces();
                    ns.Add(string.Empty, string.Empty);
                }
                ser.Serialize(w, obj, ns);
                StreamReader reader = new StreamReader(stream, encoding);
                stream.Position = 0;
                str = reader.ReadToEnd();
                stream.Close();
                reader.Close();
            }
            return str;
        }

        #endregion

        #region XmlDeserializeFromString

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xmlString"></param>
        /// <returns></returns>
        public static T XmlDeserializeFromString<T>(string xmlString)
        {
            return XmlDeserializeFromString<T>(xmlString, string.Empty);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xmlString"></param>
        /// <param name="defaultNamespace"></param>
        /// <returns></returns>
        public static T XmlDeserializeFromString<T>(string xmlString, string defaultNamespace)
        {
            return XmlDeserializeFromString<T>(xmlString, Encoding.UTF8, defaultNamespace);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xmlString"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static T XmlDeserializeFromString<T>(string xmlString, Encoding encoding)
        {
            return XmlDeserializeFromString<T>(xmlString, encoding, string.Empty);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xmlString"></param>
        /// <param name="encoding"></param>
        /// <param name="defaultNamespace"></param>
        /// <returns></returns>
        public static T XmlDeserializeFromString<T>(string xmlString, Encoding encoding, string defaultNamespace)
        {
            if (string.IsNullOrEmpty(xmlString))
                return default(T);

            if (typeof(T) == typeof(string))
                return (T)Convert.ChangeType(xmlString, typeof(T));
            try
            {
                XmlSerializer ser = new XmlSerializer(typeof(T), defaultNamespace);
                MemoryStream stream = new MemoryStream();
                StreamWriter writer = new StreamWriter(stream, encoding);
                writer.AutoFlush = true;
                writer.Write(xmlString);
                stream.Position = 0;
                T obj = (T)ser.Deserialize(stream);
                stream.Close();
                writer.Close();
                return obj;
            }
            catch
            {
                return default(T);
            }
        }

        #endregion

        #region XmlSerialize
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static XmlDocument XmlSerialize<T>(T obj)
        {
            return XmlSerialize<T>(obj, null, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static XmlDocument XmlSerialize<T>(T obj, Encoding encoding)
        {
            return XmlSerialize<T>(obj, encoding, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="ns"></param>
        /// <returns></returns>
        public static XmlDocument XmlSerialize<T>(T obj, XmlSerializerNamespaces ns)
        {
            return XmlSerialize<T>(obj, null, ns);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="ns"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static XmlDocument XmlSerialize<T>(T obj, Encoding encoding, XmlSerializerNamespaces ns)
        {
            XmlDocument doc = new XmlDocument();
            string xml = XmlSerializeToString<T>(obj, encoding, ns);
            doc.LoadXml(xml);
            return doc;
        }
        #endregion

        #region XmlDeserialize
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="doc"></param>
        /// <returns></returns>
        public static T XmlDeserialize<T>(XmlDocument doc)
        {
            return XmlDeserialize<T>(doc);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="doc"></param>
        /// <param name="defaultNamespace"></param>
        /// <returns></returns>
        public static T XmlDeserialize<T>(XmlDocument doc, string defaultNamespace)
        {
            return XmlDeserialize<T>(doc, Encoding.UTF8, defaultNamespace);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="doc"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static T XmlDeserialize<T>(XmlDocument doc, Encoding encoding)
        {
            return XmlDeserialize<T>(doc, encoding, string.Empty);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="doc"></param>
        /// <param name="encoding"></param>
        /// <param name="defaultNamespace"></param>
        /// <returns></returns>
        public static T XmlDeserialize<T>(XmlDocument doc, Encoding encoding, string defaultNamespace)
        {
            return XmlDeserializeFromString<T>(doc.OuterXml, encoding, defaultNamespace);
        }


        #endregion

        #region ToXMLString
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string ToXMLString<T>(this T obj)
        {
            return ToXMLString<T>(obj, Encoding.UTF8);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static string ToXMLString<T>(this T obj, Encoding encoding)
        {
            return ToXMLString<T>(obj, encoding, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="namespaces"></param>
        /// <returns></returns>
        public static string ToXMLString<T>(this T obj, IDictionary<string, string> namespaces)
        {
            return ToXMLString<T>(obj, Encoding.UTF8, namespaces);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="encoding"></param>
        /// <param name="namespaces"></param>
        /// <returns></returns>
        public static string ToXMLString<T>(this T obj, Encoding encoding, IDictionary<string, string> namespaces)
        {
            XmlSerializerNamespaces namespacesSer = new XmlSerializerNamespaces();
            foreach (var kv in namespaces)
            {
                namespacesSer.Add(kv.Key, kv.Value);
            }
            return XmlSerializeToString<T>(obj, encoding, namespacesSer);
        }
        #endregion

        #region ToXMLObject
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xmlString"></param>
        /// <returns></returns>
        public static T ToXMLObject<T>(this string xmlString)
        {
            return XmlDeserializeFromString<T>(xmlString);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xmlString"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static T ToXMLObject<T>(this string xmlString, Encoding encoding)
        {
            return XmlDeserializeFromString<T>(xmlString, encoding);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xmlString"></param>
        /// <param name="defaultNamespace"></param>
        /// <returns></returns>
        public static T ToXMLObject<T>(this string xmlString, string defaultNamespace)
        {
            return XmlDeserializeFromString<T>(xmlString, defaultNamespace);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xmlString"></param>
        /// <param name="encoding"></param>
        /// <param name="defaultNamespace"></param>
        /// <returns></returns>
        public static T ToXMLObject<T>(this string xmlString, Encoding encoding, string defaultNamespace)
        {
            return XmlDeserializeFromString<T>(xmlString, encoding, defaultNamespace);
        }
        #endregion
    }
}
